package oneD.t3dviewer;
/* Java3DModel.java  Representation of a 3D model as a wire frame of line
                     segments tailored for use in a Java3D environment.

   History:

   12 Jun 2008  Delete construction from InputStream.
   10 Jun 2008  Adapted from JModel3D.java.

   To do:

   Use standard constructs for managing LineSegment and Point3f lists.
 */

import java.io.*;
import javax.vecmath.*;

/**
 * The representation of a 3D model as a wire frame of line segments.
 */
public class Java3DModel extends Model3D {
	/**
	 * Radius of the figure's bounding sphere.
	 */
	public double m_radius = 1.0;
	/**
	 * Center of the figure's bounding sphere.
	 */
	public Point3d m_center = new Point3d();
	/**
	 * Origin for computations.
	 */
	public static final Point3d m_origin = new Point3d();
	/**
	 * Minimum size for point and line segment arrays.
	 */
	public static final int M_MIN_BUFFSIZE = 50;
	/**
	 * Coordinates for all points.
	 */
	public Point3d m_points[];
	/**
	 * Size of used portion of vertex arrays.
	 */
	public int m_npoints;

	/**
	 * Class for storing LineSegment data.
	 */
	public class LineSegment {
		public final int m_p1, m_p2; // end points (indices into m_points)
		public final int m_type;

		LineSegment(int p1, int p2, int type) {
			m_p1 = p1;
			m_p2 = p2;
			m_type = type;
		}

		/**
		 * Get first end point.
		 */
		Point3d p1() {
			return m_points[m_p1];
		}

		/**
		 * Get second end point.
		 */
		Point3d p2() {
			return m_points[m_p2];
		}
	}

	public LineSegment m_lineSegments[];
	public int m_nlineSegments;

	public Java3DModel() {
	}

	/**
	 * Zero vertex and lineSegment counts.
	 */
	public void reset() {
		m_npoints = 0;
		m_nlineSegments = 0;
		m_center.set(m_origin);
		m_radius = 1.0;
	}

	/**
	 * Add a point to the model's geometry.
	 * 
	 * @param x
	 *            x coordinate of point
	 * @param y
	 *            y coordinate of point
	 * @param z
	 *            z coordinate of point
	 */
	void addPoint(double x, double y, double z) {
		Point3d point = new Point3d(x, y, z);
		if (m_points == null)
			m_points = new Point3d[M_MIN_BUFFSIZE];
		else if (m_npoints >= m_points.length) {
			Point3d points[] = new Point3d[m_points.length * 2];
			System.arraycopy(m_points, 0, points, 0, m_points.length);
			m_points = points;
		}
		m_points[m_npoints++] = point;
	}

	/**
	 * Add a LineSegment with endpoints p1 and p2 to the model's geometry.
	 * 
	 * @param p1
	 *            zero-based index of first endpoint
	 * @param p2
	 *            zero-based index of second endpoint
	 * @param type
	 *            type value for this line segment
	 */
	void addLineSegment(int p1, int p2, int type) {
		LineSegment lineSegment = new LineSegment(p1, p2, type);
		if (lineSegment.m_p1 >= m_npoints || lineSegment.m_p2 >= m_npoints)
			return;
		if (m_lineSegments == null)
			m_lineSegments = new LineSegment[M_MIN_BUFFSIZE];
		else if (m_nlineSegments >= m_lineSegments.length) {
			LineSegment lineSegments[] = new LineSegment[m_lineSegments.length * 2];
			System.arraycopy(m_lineSegments, 0, lineSegments, 0,
					m_lineSegments.length);
			m_lineSegments = lineSegments;
		}
		m_lineSegments[m_nlineSegments++] = lineSegment;
	}

	void computeBoundingSphere() {
		// find model center and bounding radius
		Vector3d vec = new Vector3d();
		for (int i = 0; i < m_npoints; i++)
			m_center.add(m_points[i]);
		m_center.scale(1.0f / m_npoints);
		m_radius = 0.0;
		for (int i = 0; i < m_npoints; i++) {
			vec.sub(m_points[i], m_center);
			double length = vec.length();
			if (length > m_radius)
				m_radius = length;
		}
	}
}
